using System;
using System.Collections;

namespace EntityKit.Runtime
{
    /// <summary>
    /// 可观察的哈希表类，当哈希表内容发生变化时会触发相应的事件
    /// </summary>
    public class BindableHashtable
    {
        private Hashtable mHashtable = new Hashtable();
        
        /// <summary>
        /// 当向哈希表中添加键值对时触发的事件
        /// </summary>
        public event Action<object, object> OnItemAdded;
        
        /// <summary>
        /// 当从哈希表中移除键值对时触发的事件
        /// </summary>
        public event Action<object, object> OnItemRemoved;
        
        /// <summary>
        /// 当哈希表中某个键的值被替换时触发的事件
        /// </summary>
        public event Action<object, object, object> OnItemReplaced; // key, oldValue, newValue
        
        /// <summary>
        /// 当哈希表被清空时触发的事件
        /// </summary>
        public event Action OnCleared;
        
        /// <summary>
        /// 当哈希表内容发生任何变化时触发的事件
        /// </summary>
        public event Action OnChanged;
        
        /// <summary>
        /// 获取哈希表中键值对的数量
        /// </summary>
        public int Count => mHashtable.Count;
        
        /// <summary>
        /// 获取或设置与指定键关联的值
        /// </summary>
        /// <param name="key">要获取或设置其值的键</param>
        /// <returns>与指定键相关联的值</returns>
        public object this[object key]
        {
            get => mHashtable[key];
            set
            {
                if (mHashtable.ContainsKey(key))
                {
                    object oldValue = mHashtable[key];
                    mHashtable[key] = value;
                    OnItemReplaced?.Invoke(key, oldValue, value);
                }
                else
                {
                    mHashtable[key] = value;
                    OnItemAdded?.Invoke(key, value);
                }
                OnChanged?.Invoke();
            }
        }
        
        /// <summary>
        /// 获取包含哈希表中所有键的集合
        /// </summary>
        public ICollection Keys => mHashtable.Keys;
        
        /// <summary>
        /// 获取包含哈希表中所有值的集合
        /// </summary>
        public ICollection Values => mHashtable.Values;
        
        /// <summary>
        /// 向哈希表中添加键值对
        /// </summary>
        /// <param name="key">要添加的键</param>
        /// <param name="value">要添加的值</param>
        public void Add(object key, object value)
        {
            mHashtable.Add(key, value);
            OnItemAdded?.Invoke(key, value);
            OnChanged?.Invoke();
        }
        
        /// <summary>
        /// 从哈希表中移除具有指定键的元素
        /// </summary>
        /// <param name="key">要移除的元素的键</param>
        public void Remove(object key)
        {
            if (mHashtable.ContainsKey(key))
            {
                object value = mHashtable[key];
                mHashtable.Remove(key);
                OnItemRemoved?.Invoke(key, value);
                OnChanged?.Invoke();
            }
        }
        
        /// <summary>
        /// 清空哈希表中的所有键值对
        /// </summary>
        public void Clear()
        {
            mHashtable.Clear();
            OnCleared?.Invoke();
            OnChanged?.Invoke();
        }
        
        /// <summary>
        /// 确定哈希表是否包含具有指定键的元素
        /// </summary>
        /// <param name="key">要在哈希表中定位的键</param>
        /// <returns>如果哈希表包含具有指定键的元素，则为true；否则为false</returns>
        public bool ContainsKey(object key)
        {
            return mHashtable.ContainsKey(key);
        }
        
        /// <summary>
        /// 确定哈希表是否包含特定值
        /// </summary>
        /// <param name="value">要在哈希表中定位的值</param>
        /// <returns>如果哈希表包含具有指定值的元素，则为true；否则为false</returns>
        public bool ContainsValue(object value)
        {
            return mHashtable.ContainsValue(value);
        }
        
        /// <summary>
        /// 获取一个枚举器，用于遍历哈希表
        /// </summary>
        /// <returns>可用于遍历哈希表的枚举器</returns>
        public IDictionaryEnumerator GetEnumerator()
        {
            return mHashtable.GetEnumerator();
        }
        
        /// <summary>
        /// 返回哈希表中所有键值对的字符串表示形式
        /// </summary>
        /// <returns>哈希表的字符串表示形式</returns>
        public override string ToString()
        {
            return $"BindableHashtable (Count: {Count})";
        }
    }
}